package com.uroboros.spring.guides.rest.employee2;

import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.linkTo;
import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.methodOn;

import java.util.List;
import org.springframework.hateoas.CollectionModel;
import org.springframework.hateoas.EntityModel;
import org.springframework.hateoas.IanaLinkRelations;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class Employee2Controller {

  private final Employee2Repository repository;
  private final Employee2ModelAssembler assembler;

  public Employee2Controller(Employee2Repository repository, Employee2ModelAssembler assembler) {
    this.repository = repository;
    this.assembler = assembler;
  }

  @GetMapping("/employee2s")
  List<Employee2> all() {
    return repository.findAll();
  }

  @PostMapping("/employee2s")
  ResponseEntity<?> newEmployee2(@RequestBody Employee2 newEmployee2) {
    EntityModel<Employee2> entityMode = assembler.toModel(repository.save(newEmployee2));
    return ResponseEntity
        .created(entityMode.getRequiredLink(IanaLinkRelations.SELF).toUri())
        .body(entityMode);
  }


  @GetMapping("/employee2s/{id}")
  Employee2 one(@PathVariable Long id) {
    return repository.findById(id).orElseThrow(() -> new Employee2NotFoundException(id));
  }

  @PutMapping("/employee2s/{id}")
  ResponseEntity<?> replaceEmployee2(@RequestBody Employee2 newEmployee2, @PathVariable Long id) {
    Employee2 updatedEmployee2 = repository.findById(id)
        .map(employee2 -> {
          employee2.setName(newEmployee2.getName());
          employee2.setRole(newEmployee2.getRole());
          return repository.save(employee2);
        })
        .orElseGet(() -> repository.save(newEmployee2));

    EntityModel<Employee2> entityMode2 = assembler.toModel(updatedEmployee2);

    return ResponseEntity
        .created(entityMode2.getRequiredLink(IanaLinkRelations.SELF).toUri()) //
        .body(entityMode2);
  }

  @DeleteMapping("/employee2s/{id}")
  ResponseEntity<?> deleteEmployee2(@PathVariable Long id) {
    repository.deleteById(id);
    return ResponseEntity.noContent().build();
  }

  /**
   * 超链接驱动的获取单个员工信息
   */
  @GetMapping("/hateoas/employee2s/{id}")
  EntityModel<Employee2> oneByHypermediaDriven(@PathVariable Long id) {
    Employee2 employee2 = repository.findById(id).orElseThrow(() -> new Employee2NotFoundException(id));

    return EntityModel.of(employee2,
        linkTo(methodOn(Employee2Controller.class).one(id)).withSelfRel(),
        linkTo(methodOn(Employee2Controller.class).all()).withRel("employee2s"));
  }

  /**
   * 超链接驱动的获取所有员工信息
   */
  @GetMapping("/hateoas/employee2s")
  CollectionModel<EntityModel<Employee2>> allByHypermediaDriven() {
    List<EntityModel<Employee2>> employee2s = repository.findAll().stream()
        .map(employee2 -> EntityModel.of(employee2,
            linkTo(methodOn(Employee2Controller.class).oneByHypermediaDriven(employee2.getId())).withSelfRel(),
            linkTo(methodOn(Employee2Controller.class).allByHypermediaDriven()).withRel("employee2s"))).toList();
    return CollectionModel.of(employee2s, linkTo(methodOn(Employee2Controller.class).allByHypermediaDriven()).withSelfRel());
  }

  /**
   * 超链接驱动的获取单个员工信息（简化）
   */
  @GetMapping("/hateoas/simplify/employee2s/{id}")
  EntityModel<Employee2> oneByHypermediaDrivenSimplify(@PathVariable Long id) {
    return assembler.toModel(repository.findById(id).orElseThrow(() -> new Employee2NotFoundException(id)));
  }

  /**
   * 超链接驱动的获取所有员工信息（简化）
   */
  @GetMapping("/hateoas/simplify/employee2s")
  CollectionModel<EntityModel<Employee2>> allByHypermediaDrivenSimplify() {
    return assembler.toCollectionModel(repository.findAll());
  }

}